<template>
	<div class="group-voice-chat-container">
		<!-- 群聊-通话中界面 -->
		<div class="voice-container" v-if="isInCall">
			<div class="call-info">
				<div class="call-title">{{ groupInfo.groupName || '微信群语音聊天1' }}</div>
				<div class="call-status time">{{ callDuration }}</div>
			</div>

			<!-- 主说话人视图 -->
			<div class="speaker-view">
				<img :src="mainSpeakerAvatar" alt="主说话人" class="main-speaker">
			</div>

			<!-- 成员列表 -->
			<div class="group-members">
				<!-- 本地用户 -->
				<div class="member-item">
					<img :src="userInfo.avatar || defaultAvatar" :class="['member-avatar', localSpeaking ? 'speaking' : '']"
						alt="我的头像">
					<div class="member-name">我</div>
					<div class="member-status">{{ isMuted ? '已静音' : '在线' }}</div>
				</div>

				<!-- 远程用户 -->
				<div class="member-item" v-for="(user, uid) in remoteUsers" :key="uid">
					<img :src="getUserAvatar(uid)" :class="['member-avatar', user.isSpeaking ? 'speaking' : '']"
						:alt="`${getUserName(uid)}的头像`">
					<div class="member-name">{{ getUserName(uid) }}--</div>
					<div class="member-status">{{ user.isSpeaking ? '正在说话' : '在线' }}</div>
				</div>
			</div>

			<!-- 控制按钮 -->
			<div class="control-buttons">
				<button class="control-button mute" :class="{ active: isMuted }" @click="toggleMute">
					<img class="fa" :src="isMuted ? '/static/images/microphone-slash.svg' : '/static/images/microphone.svg'"
						alt="" />
					<span>{{ isMuted ? '取消静音' : '静音' }}</span>
				</button>
				<button class="control-button speaker" :class="{ active: isSpeakerOn }" @click="toggleSpeaker">
					<img class="fa" :src="isSpeakerOn ? '/static/images/volume-up.svg' : '/static/images/volume-off.svg'"
						alt="" />
					<span>{{ isSpeakerOn ? '关闭扬声器' : '扬声器' }}</span>
				</button>
				<button class="control-button invite" @click="inviteMore">
					<img class="fa" src="/static/images/user-plus.svg" alt="" />
					<span>邀请</span>
				</button>
				<button class="control-button end-call" @click="endCall">
					<img class="fa" src="/static/images/phone-slash.svg" alt="" />
					<span>挂断</span>
				</button>
			</div>
		</div>

		<!--群语音-来电界面 -->
		<view id="incoming-call" v-if="showIncomingCall">
			<view class="incoming-call">
				<img :src="groupInfo.groupAvatar || defaultGroupAvatar" alt="群头像" class="caller-avatar">
				<div class="caller-name">{{ groupInfo.groupName || '微信群聊' }}</div>
				<div class="call-status">群语音通话邀请...</div>
				<div class="call-members">
					<span>成员: {{ memberNames }}</span>
					<div>
						{{ memberNames }}--{{memberid}}
					</div>
				</div>
				<!-- 接听、挂断 -->
				<div class="answer-buttons">
					<div class="decline-call" @click="declineCall">
						<img class="fa" src="/static/images/phone-slash.svg" alt="" />
					</div>
					<div class="accept-call" @click="acceptCall" v-if="!isSelf"> 
						<img class="fa" src="/static/images/phone.svg" alt="" />
					</div>
				</div>
			</view>
		</view>

		<!-- 加载指示器 -->
		<div class="loading" v-if="isLoading">{{ loadingMessage }}</div>

		<!-- toast提示 -->
		<div class="toast" :class="{ show: showToast }">
			<div class="toast-content">
				<p>{{ toastMessage }}</p>
			</div>
		</div>
	</div>
</template>

<script>
	import AgoraRTC from 'agora-rtc-sdk-ng';

	export default {
		name: 'GroupVoiceChat',
		props: {
			channelInfo: {
				type: Object,
				required: true
			},
			userInfo: {
				type: Object,
				required: true
			},
			groupInfo: {
				type: Object,
				required: true
			},
			isSelf: {
				type: Boolean,
				default: false
			}
		},
		data() {
			return {
				isInCall: false,
				showIncomingCall: true,
				isLoading: false,
				loadingMessage: '正在连接...',
				showToast: false,
				toastMessage: '',
				callDuration: '00:00:00',
				isMuted: false,
				isSpeakerOn: false,
				localSpeaking: false,
				seconds: 0,
				callTimer: null,
				client: null,
				localAudioTrack: null,
				remoteUsers: {},
				currentMainSpeaker: null,
				params: {},
				defaultAvatar: 'https://img.buildmost.com/image/20211013/419cf426-5fff-4a90-8e7f-18ea48c113b3.jpeg',
				defaultGroupAvatar: 'https://hkimg.buildmost.com/image/20240705/3849f2b7-2a6d-493a-adb0-511c3787cd6f.jpg?x-image-process=image/colorspace,cmyk/resize,w_356,h_252'//群头像
			};
		},
		computed: {
			mainSpeakerAvatar() {//讲话人-头像  13428766701
			console.log('currentMainSpeaker',this.currentMainSpeaker);
				if (this.currentMainSpeaker) {
					const speaker = this.remoteUsers[this.currentMainSpeaker];
					console.log('speaker',speaker);
					if (speaker) {
						return this.getUserAvatar(this.currentMainSpeaker);
					}
				}
				return this.defaultGroupAvatar;
			},
			memberNames() {//群成员-name获取
				if (this.groupInfo.members) {
					return this.groupInfo.members.map(m => m.name).join(', '				);
				}
				return '';
			},
			memberid(){//群成员-id获取
				if (this.groupInfo.members) {
					return this.groupInfo.members.map(m => m.id).join(', ');
				}
				return '';
			},
		},
		created() {
			this.playRingtone();
		},
		beforeUnmount() {
			this.cleanup();
		},
		methods: {
			playRingtone() {
				console.log("播放来电铃声...");
			},
			
			/**
			 * 群邀请 
			 * **/
			// 电话-接听电话
			async acceptCall() {
				console.log('接听电话-群聊');
				await this.joinChannel();
			},
			// 电话-挂断
			declineCall() {
				this.showIncomingCall = false;
				this.$emit('call-action', {
					callerId: "caller",
					status: false,
					timestamp: Date.now(),
					userId: this.userInfo.id,
					type: 'group_voice'
				});
				this.leaveChannel()
			},
			// 挂断
			endCall() {
				console.log('群-挂断');
				this.handeUp(this.userInfo.id);
			},
			toggleMute() {
				this.isMuted = !this.isMuted;
				if (this.localAudioTrack) {
					this.localAudioTrack.setVolume(this.isMuted ? 0 : 100);
				}
			},
			// 是否打开扬声器
			toggleSpeaker() {
				this.isSpeakerOn = !this.isSpeakerOn;
				this.updateRemoteAudioVolume(this.isSpeakerOn ? 100 : 50);
			},
			// 邀请事件
			inviteMore() {
				this.$emit('call-action', {
					callerId: "invite",
					timestamp: Date.now(),
					userId: this.userInfo.id,
					type: 'group_voice'
				});
			},
			// 挂断
			handeUp(userUid) {
				console.log('挂断--',userUid);
				this.isInCall = false;
				this.$emit('call-action', {
					callerId: "handelUp",
					status: false,
					timestamp: Date.now(),
					userId: userUid,
					type: 'group_voice'
				});
				this.cleanup()
			},
			// 语音通话开始计时
			startCallTimer() {
				this.seconds = 0;
				this.callTimer = setInterval(() => {
					this.seconds++;
					const hours = Math.floor(this.seconds / 3600);
					const minutes = Math.floor((this.seconds % 3600) / 60);
					const secs = this.seconds % 60;
					this.callDuration =
						`${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
				}, 1000);
			},
			// 停止通话计时
			stopCallTimer() {
				if (this.callTimer) {
					clearInterval(this.callTimer);
					this.callTimer = null;
				}
			},
			// 加入频道
			async joinChannel() {
				console.log('已接听-频道信息',this.channelInfo);
				const {
					appId,
					channel,
					token
				} = this.channelInfo;
				const userId = this.userInfo.id;

				if (!appId || !channel) {
					console.log("App ID 和频道名不能为空");
					return;
				}

				try {
					this.showLoading("正在连接...");
					const devices = await AgoraRTC.getMicrophones();
					if (devices.length === 0) {
						console.log('未找到麦克风设备');
						this.handleJoinError(userId, '未找到麦克风设备');
						return;
					}

					AgoraRTC.setLogLevel(2);// 声网设置日志级别-设置日志输出等级
					/**
					 * 1.创建本地客户端
					 * 初始化引擎，创建纯音频客户端
					 * 引入声网SDK,通过createClient()传递配置参数生成端口
					 * */
					this.client = AgoraRTC.createClient({
						mode: "rtc",
						codec: "vp8"
					});
					
					console.log("正在加入频道",{appId},{channel},{token},{userId});
					// 2.加入频道
					const uid = await this.client.join(appId, channel, token || null, userId);
					console.log('本地用户ID', uid);
					//其他用户加入- 设置事件监听
					this.setupClientEvents();
				} catch (error) {
					console.log(`加入频道失败: ${error.message}`);
					this.handleJoinError(userId, '连接失败');
					this.stopCallTimer();// 停止通话计时
				}
			},
			// 设置事件监听
			setupClientEvents() {
				// 用户加入事件
				this.client.on("user-joined", async (user) => {
					console.log(`远程用户 ${user.uid} 加入了频道`);
					if (this.client.remoteUsers.length >= 1) {
						await this.publishAudio();
						this.showIncomingCall = false;
						this.isInCall = true;
					}
				});
				/**
				 * 订阅音轨
				 * 这样可以收听到其它用户声音，注意时间额度用光后，这里是进不来的
				 * 监听用户加入并发布音频流事件
				 */
				console.log('拿到远端用户对象-加入频道并发布音频轨道,远程端反应，发布', );
				this.client.on("user-published", async (user, mediaType) => {//获取远端用户 AgoraRTCRemoteUser 对象 。
					/**
					 * 声网IP/ID每日免费额度到了后这里进不来（大坑）
					 * 
					 * mediaType
					 * "video": 订阅指定用户发布的视频轨道。
					 * "audio": 订阅指定用户发布的音频轨道。
					 * **/
					console.log('==== start subscribe audio track ====',mediaType)
					// 表示本次订阅的是音频。
					if (mediaType === "audio") {
						// 6.开始订阅远端用户的音视频轨道。
						await this.client.subscribe(user, mediaType);
						console.log(`远程用户 ${user.uid} 发布了音频流`);
						// 5.获取远端用户对象
						this.$set(this.remoteUsers, user.uid, {
							user: user,
							audioTrack: user.audioTrack,//7.获取远端用户对象
							isSpeaking: false,
							speakingLevel: 0
						});
						// 播放远程音频
						user.audioTrack.play();
						 //语音通话开始计时
						if (Object.keys(this.remoteUsers).length === 1) {
							this.startCallTimer();
						}
					}
				});
				// 监听用户取消发布音频流事件
				this.client.on("user-unpublished", (user, mediaType) => {
					if (mediaType === "audio") {
						console.log(`远程用户 ${user.uid} 取消了音频流`);
						this.$delete(this.remoteUsers, user.uid);

						if (this.currentMainSpeaker === user.uid) {
							this.currentMainSpeaker = null;
						}

						if (Object.keys(this.remoteUsers).length > 0) {
							this.showToast(`${this.getUserName(user.uid)} 已离开`);
						} else {
							this.handeUp('');
						}
					}
				});
				// 监听用户离开事件
				this.client.on("user-left", (user) => {
					console.log(`远程用户 ${user.uid} 已离开`);
					this.$delete(this.remoteUsers, user.uid);

					if (this.currentMainSpeaker === user.uid) {
						this.currentMainSpeaker = null;
					}

					if (Object.keys(this.remoteUsers).length > 0) {
						this.showToast(`${this.getUserName(user.uid)} 已离开`);
					} else {
						this.handeUp('');
					}
				});

				this.client.enableAudioVolumeIndicator();
				this.client.on("volume-indicator", (volumes) => {
					volumes.forEach((volume) => {
						if (volume.uid === this.userInfo.id) {
							this.updateLocalSpeakingStatus(volume.level > 5);
						} else {
							if (this.remoteUsers[volume.uid]) {
								this.remoteUsers[volume.uid].speakingLevel = volume.level;
								this.remoteUsers[volume.uid].isSpeaking = volume.level > 5;

								if (volume.level > 5 && (!this.currentMainSpeaker ||
										volume.level > (this.remoteUsers[this.currentMainSpeaker]?.speakingLevel || 0))) {
									this.currentMainSpeaker = volume.uid;
								}
							}
						}
					});
				});
				// 网络质量检测
				this.client.on("network-quality", (stats) => {
					this.updateNetworkStatus(stats);
				});
			},
			// 发布本地音频流
			async publishAudio() {
				if (!this.client) {
					console.log("请先加入频道");
					return;
				}
				try {
					console.log("正在获取麦克风权限...");
					// 3.通过麦克风采集的音频创建本地音频轨道对象
					this.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack({
						encoderConfig: "speech_standard",// 语音优化配置
						AEC: true, // 回声消除
						ANS: true// 降噪
					});
					// 设置初始音量
					this.localAudioTrack.setVolume(100);
					// 监听本地音频音量变化
					this.localAudioTrack.on("volume-change", (volume) => {
						this.updateLocalSpeakingStatus(volume > 50);
					});
					// 发布本地音频轨道
					console.log("正在发布本地音频流...");
					// 4.然后调用 publish 方法，将这些本地音频轨道对象当作参数即可将音频发布到频道中。
					await this.client.publish([this.localAudioTrack]);
					console.log("本地音频流已发布,本地用户" + this.userInfo.id);
					this.hideLoading();
				} catch (error) {
					console.log(`发布音频流失败: ${error.message}`);
					this.handlePublishError(this.userInfo.id, '获取麦克风权限失败');
					this.stopCallTimer();// 停止通话计时
				}
			},
			// 取消发布本地音频流
			async unpublishAudio() {
				if (!this.client) {
					console.log("客户端未初始化");
					return;
				}
				try {
					console.log("正在取消发布本地音频流...");
					if (this.localAudioTrack) {
						await this.client.unpublish([this.localAudioTrack]);
						this.localAudioTrack.close();//8.关闭本地音频轨道
						this.localAudioTrack = null;
					}
					console.log("已取消发布本地音频流");
				} catch (error) {
					console.log(`取消发布失败: ${error.message}`);
				}
			},
			// 离开频道
			async leaveChannel() {
				if (!this.client) {
					console.log("客户端未初始化");
					return;
				}
				try {
					console.log("开始挂断流程...");
					await this.unpublishAudio();
					await this.client.leave();
					this.client = null;
					this.remoteUsers = {};
				} catch (error) {
					console.error("挂断过程中出错:", error);
					// 即使出错也尝试强制清理
					this.forceCleanup();
				}
			},
			// 强制清理资源
			forceCleanup() {
				console.log('挂断过程中出错,强制清理--');
				if (this.localAudioTrack) {
					this.localAudioTrack.close();
					this.localAudioTrack = null;
				}

				if (this.client) {
					this.client.leave();
					this.client = null;
				}

				this.remoteUsers = {};
			},
			// 清理资源
			cleanup() {
				this.stopCallTimer();// 停止通话计时
				this.leaveChannel();// 离开频道
			},
			// ？设置初始音量
			updateRemoteAudioVolume(volume) {
				console.log('扬声器',volume);
				Object.values(this.remoteUsers).forEach(user => {
					if (user.audioTrack) {
						user.audioTrack.setVolume(volume);
					}
				});
			},
			// 监听本地音频音量变化-调用
			updateLocalSpeakingStatus(isSpeaking) {
				console.log('本地音频音量',isSpeaking);
				this.localSpeaking = isSpeaking;
			},
			// 获取远程头像
			getUserName(uid) {
				if (uid === this.userInfo.id) return '我';
				if (this.groupInfo.members) {
					const member = this.groupInfo.members.find(m => m.id === uid);
					if (member) return member.name;
				}
				return `用户${uid}`;
			},
			// 远程用户头像
			getUserAvatar(uid) {
				console.log({uid});
				if (uid === this.userInfo.id) return this.userInfo.avatar || this.defaultAvatar;
				if (this.groupInfo.members) {
					const member = this.groupInfo.members.find(m => m.id === uid);
					if (member) return member.avatar;
				}
				// 默认头像
				return this.defaultAvatar;
			},
			// 连接失败：麦克风、
			handleJoinError(userId, error) {
				this.$emit('call-action', {
					callerId: "groupAudioCall",
					status: false,
					timestamp: Date.now(),
					userId: userId,
					error: error
				});
			},
			// 获取权限失败：麦克风
			handlePublishError(userId, error) {
				this.$emit('call-action', {
					callerId: "groupAudioCall",
					status: false,
					timestamp: Date.now(),
					userId: userId,
					error: error
				});
			},
			// 更新网络状态显示
			updateNetworkStatus(stats) {
				if (stats.downlinkNetworkQuality > 4) {
					this.showToast('网络较差');
				}
				if (stats.downlinkNetworkQuality > 6) {
					this.showToast('网络非常差');
				}
			},
			// 显示提示消息-调用
			showLoading(message) {
				this.loadingMessage = message;
				this.isLoading = true;
			},
			// 已发布-关闭提示
			hideLoading() {
				this.isLoading = false;
			},
			// 提示框
			showToast(message) {
				this.toastMessage = message;
				// this.showToast = true;
				setTimeout(() => {
					uni.showToast({
						title: message,
						icon: 'none'
					})
				}, 1000);
			}
		}
	};
</script>

<style scoped>
	.group-voice-chat-container {
		position: relative;
		width: 100%;
		height: 100%;
		background-color: #f5f5f5;
	}

	.voice-container {
		position: relative;
		width: 100%;
		height: 100%;
		background-color: #333;
		padding: 20px;
		box-sizing: border-box;
	}

	.call-info {
		text-align: center;
		margin-bottom: 20px;
		color: white;
	}

	.call-title {
		font-size: 18px;
		margin-bottom: 5px;
	}

	.call-status {
		font-size: 14px;
		color: #aaa;
	}

	.speaker-view {
		position: relative;
		width: 100%;
		height: 150px;
		margin-bottom: 20px;
		display: flex;
		justify-content: center;
		align-items: center;
	}

	.main-speaker {
		width: 120px;
		height: 120px;
		border-radius: 50%;
		object-fit: cover;
		border: 3px solid #09bb07;
		box-shadow: 0 0 15px rgba(9, 187, 7, 0.7);
	}

	.group-members {
		display: flex;
		flex-wrap: wrap;
		justify-content: center;
		margin: 20px 0;
		gap: 15px;
	}

	.member-item {
		display: flex;
		flex-direction: column;
		align-items: center;
		width: 80px;
	}

	.member-avatar {
		width: 60px;
		height: 60px;
		border-radius: 50%;
		object-fit: cover;
		border: 2px solid #ddd;
		transition: all 0.3s;
	}

	.member-avatar.speaking {
		border-color: #09bb07;
		box-shadow: 0 0 10px rgba(9, 187, 7, 0.5);
	}

	.member-name {
		margin-top: 5px;
		font-size: 12px;
		color: #fff;
		text-align: center;
		width: 100%;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	.member-status {
		font-size: 10px;
		color: #aaa;
	}

	.control-buttons {
		display: flex;
		justify-content: space-around;
		width: 100%;
		padding: 0 20px;
		position: fixed;
		bottom: 30px;
		left: 0;
		right: 0;
	}

	.control-button {
		display: flex;
		flex-direction: column;
		align-items: center;
		background: rgba(255, 255, 255, 0.1);
		border: none;
		border-radius: 50%;
		width: 60px;
		height: 60px;
		color: white;
		font-size: 12px;
	}

	.control-button img {
		width: 24px;
		height: 24px;
		margin-bottom: 5px;
		filter: brightness(0) invert(1);
	}

	.control-button.end-call {
		background: #f44336;
	}

	.control-button.active {
		background: rgba(9, 187, 7, 0.3);
	}

	/* 来电振动动画 */
	@keyframes vibrate {
		0% {
			transform: rotate(0deg);
		}

		25% {
			transform: rotate(2deg);
		}

		50% {
			transform: rotate(0deg);
		}

		75% {
			transform: rotate(-2deg);
		}

		100% {
			transform: rotate(0deg);
		}
	}

	.incoming-call {
		animation: vibrate 0.3s infinite;
		text-align: center;
	}

	#incoming-call {
		position: fixed;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
		background-color: #1a1a1a;
		color: white;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		z-index: 1000;
	}

	.caller-info {
		text-align: center;
		padding: 20px;
	}

	.caller-avatar {
		width: 120px;
		height: 120px;
		border-radius: 60px;
		margin-bottom: 20px;
	}

	.caller-name {
		font-size: 20px;
		margin-bottom: 10px;
	}

	.call-status {
		font-size: 16px;
		color: #aaa;
		margin-bottom: 10px;
	}

	.call-members {
		font-size: 14px;
		color: #ccc;
		margin-bottom: 30px;
	}

	.answer-buttons {
		display: flex;
		gap: 40px;
	}

	.decline-call,
	.accept-call {
		width: 60px;
		height: 60px;
		border-radius: 30px;
		display: flex;
		align-items: center;
		justify-content: center;
		cursor: pointer;
	}
	.decline-call img,
	.accept-call img {
		width: 30px;
		height: 30px;
		filter: brightness(0) invert(1);
	}
	.decline-call {
		background: #ff3b30;
	}

	.accept-call {
		background: #34c759;
	}

	.loading {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background-color: rgba(0, 0, 0, 0.7);
		display: flex;
		align-items: center;
		justify-content: center;
		color: white;
		z-index: 30;
	}

	.toast {
		position: fixed;
		bottom: 100px;
		left: 50%;
		transform: translateX(-50%);
		background: rgba(0, 0, 0, 0.7);
		color: white;
		padding: 10px 20px;
		border-radius: 20px;
		z-index: 40;
		opacity: 0;
		transition: opacity 0.3s;
	}

	.toast.show {
		opacity: 1;
	}
</style>